package com.dingwen.treasure.kettle.base.web;

import com.dingwen.treasure.kettle.base.exception.AbstractBaseRuntimeException;
import com.dingwen.treasure.kettle.base.vo.ResultGenerator;
import com.dingwen.treasure.kettle.base.vo.Result;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;

/**
 * 全局异常处理 </br>
 *
 * @author dingwen
 * @date 2021.06.29 10:18
 */
@RestControllerAdvice
@Slf4j
@RequiredArgsConstructor
public class GlobalExceptionHandler {

    @ExceptionHandler(value = Exception.class)
    public Result<String> exceptionHandler(HttpServletRequest request, Exception exception) {
        StringBuilder builder = new StringBuilder();
        //接口地址
        String url = request.getRequestURI().substring(request.getContextPath().length());
        //堆栈信息
        String stackTracesMsg = printStackTraces(exception);
        //userId
        String userId = "123456";
        builder.append("userId: ").append(userId).append("\n")
                .append("requestUri: ")
                .append(url)
                .append("\n")
                .append(stackTracesMsg);

        // 堆栈日志打印
        log.error(builder.toString());

        // 异常处理： 统一结果返回
        if (exception instanceof AbstractBaseRuntimeException) {
            return ResultGenerator.genFailureResult(exception.getMessage(), ((AbstractBaseRuntimeException) exception).getCode());
        } else if (exception instanceof MethodArgumentNotValidException) {
            MethodArgumentNotValidException ex = (MethodArgumentNotValidException) exception;
            return ResultGenerator.genFailureResult(handlerMethodArgumentNotValidException(ex));
        }
        return ResultGenerator.genFailureResult(exception.getMessage());

    }

    /**
     * 最多打印7层堆栈信息
     *
     * @param e 异常
     * @return 异常信息
     */
    private String printStackTraces(Exception e) {
        StackTraceElement[] stackTraces = e.getStackTrace();
        StringBuilder builder = new StringBuilder();
        builder.append(e.getClass().getName())
                .append(": ")
                .append(e.getLocalizedMessage())
                .append("\n");
        for (StackTraceElement stackTrace : stackTraces) {
            String lineMsg = "         at ";
            lineMsg = lineMsg + stackTrace.getClassName()
                    + "(" + stackTrace.getFileName() + ":"
                    + stackTrace.getLineNumber() + ")\n";
            builder.append(lineMsg);
        }
        return builder.toString();
    }

    /**
     * 方法入参异常处理
     *
     * @param ex 异常
     * @return {@link String}
     */
    private String handlerMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
        StringBuilder stringBuilder = new StringBuilder();
        ex.getBindingResult().getFieldErrors()
                .forEach(ele -> stringBuilder
                        .append(ele.getField())
                        .append(":")
                        .append(ele.getDefaultMessage())
                        .append("  "));
        return stringBuilder.toString();
    }

}
